﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Engine.Dtd.Schema;
using System.Diagnostics;
using Engine.Sgml.Configuration;
using Engine.Sgml.Allocation;
using Engine.Sgml.Matching;
using Engine.Sgml.Merging;

namespace Engine.Sgml.Validation.Rules {
    [DebuggerDisplay("Name = {Name}")]
    class DefaultRule : IValidationRule {
        [DebuggerBrowsable(DebuggerBrowsableState.Never)]
        private ValidatorBehavior settings;

        public DefaultRule(ValidatorBehavior settings) {
            Guard.ArgumentNotNull(settings, "settings");
            this.settings = settings;
            this.Name = SName.Empty;
            }

        protected DefaultRule(SName name, ValidatorBehavior settings)
            : this(settings) {
            Guard.ArgumentNotNull(name, "name");
            Name = name;
            }

        public SName Name { get; private set; }

        public virtual bool Ignore(SElement element, SElement ancestor) {
            Guard.ArgumentNotNull(element, "element");
            Guard.ArgumentNotNull(ancestor, "ancestor");
            if (settings.RemoveIllegalElements)
                return !element.DefinedInScheme;
            else
                return false;
            }

        public bool IsEmpty(SElement element) {
            Guard.ArgumentNotNull(element, "element");
            return element.ContentModelType() == DContentModelType.Empty;
            }

        public virtual bool CanClose(SElement element, SElement endElement) {
            Guard.ArgumentNotNull(element, "element");
            Guard.ArgumentNotNull(endElement, "endElement");

            if (ElementMatcher.Match(element, endElement))
                return true;
            if (endElement.ContentModelType() == DContentModelType.Empty)
                return false;
            if (element.EndTagOptional())
                return true;

            SElement parent = element.Parent;
            if (parent != null)
                do {
                    if (ElementMatcher.Match(parent, endElement))
                        return true;
                    parent = parent.Parent;
                    } while (parent != null);
            return false;
            }

        public virtual bool CanContain(SElement element, SElement ancestor) {
            Guard.ArgumentNotNull(element, "element");
            Guard.ArgumentNotNull(ancestor, "ancestor");

            // If the element doesn't present in a current DTD scheme
            // allow to allocate it anywhere
            if (!element.DefinedInScheme)
                return true;
            if (!ancestor.DefinedInScheme) {
                if (ancestor.NodeType == SgmlNodeType.Element ||
                    ancestor.NodeType == SgmlNodeType.Document)
                    return true;
                else
                    return false;
                }
            return ancestor.Declaration.ContentModel.Exists(element.DName);
            }

        public virtual bool CanSurround(InconsistentBlock block, SElement ancestor) {
            return false;
            }

        public virtual bool Surround(InconsistentBlock block, SElement ancestor) {
            return false;
            }
        }
    }
